package com.bugsnag.ohos;

import ohos.app.Context;
import ohos.app.Environment;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

/**
 * ManifestConfigLoader
 *
 * @since 2021-07-05
 */
public class ManifestConfigLoader {
    private static final String BUGSNAG_NS = "com.bugsnag.ohos";
    /**
     * build uuid
     */
    public static final String BUILD_UUID = BUGSNAG_NS + ".BUILD_UUID";
    private static final String API_KEY = BUGSNAG_NS + ".API_KEY";
    private static final String AUTO_TRACK_SESSIONS = BUGSNAG_NS + ".AUTO_TRACK_SESSIONS";
    private static final String AUTO_DETECT_ERRORS = BUGSNAG_NS + ".AUTO_DETECT_ERRORS";
    private static final String PERSIST_USER = BUGSNAG_NS + ".PERSIST_USER";
    private static final String SEND_THREADS = BUGSNAG_NS + ".SEND_THREADS";
    private static final String ENDPOINT_NOTIFY = BUGSNAG_NS + ".ENDPOINT_NOTIFY";
    private static final String ENDPOINT_SESSIONS = BUGSNAG_NS + ".ENDPOINT_SESSIONS";
    private static final String APP_VERSION = BUGSNAG_NS + ".APP_VERSION";
    private static final String VERSION_CODE = BUGSNAG_NS + ".VERSION_CODE";
    private static final String RELEASE_STAGE = BUGSNAG_NS + ".RELEASE_STAGE";
    private static final String ENABLED_RELEASE_STAGES = BUGSNAG_NS + ".ENABLED_RELEASE_STAGES";
    private static final String DISCARD_CLASSES = BUGSNAG_NS + ".DISCARD_CLASSES";
    private static final String PROJECT_PACKAGES = BUGSNAG_NS + ".PROJECT_PACKAGES";
    private static final String REDACTED_KEYS = BUGSNAG_NS + ".REDACTED_KEYS";

    // misc
    private static final String MAX_BREADCRUMBS = BUGSNAG_NS + ".MAX_BREADCRUMBS";
    private static final String MAX_PERSISTED_EVENTS = BUGSNAG_NS + ".MAX_PERSISTED_EVENTS";
    private static final String MAX_PERSISTED_SESSIONS = BUGSNAG_NS + ".MAX_PERSISTED_SESSIONS";
    private static final String LAUNCH_CRASH_THRESHOLD_MS = BUGSNAG_NS + ".LAUNCH_CRASH_THRESHOLD_MS";
    private static final String LAUNCH_DURATION_MILLIS = BUGSNAG_NS + ".LAUNCH_DURATION_MILLIS";
    private static final String SEND_LAUNCH_CRASHES_SYNCHRONOUSLY = BUGSNAG_NS + ".SEND_LAUNCH_CRASHES_SYNCHRONOUSLY";
    private static final String APP_TYPE = BUGSNAG_NS + ".APP_TYPE";
    private static Properties prop = new Properties();

    /**
     * load configuration
     *
     * @param context
     * @param userSuppliedApiKey
     * @return Configuration
     * @throws IllegalArgumentException
     */
    public Configuration load(Context context, String userSuppliedApiKey) {
        Configuration configuration = null;
        if (!TextUtils.isEmpty(userSuppliedApiKey)) {
            configuration = new Configuration(userSuppliedApiKey);
        }
        try {
            ResourceManager resManager = context.getResourceManager();
            RawFileEntry rawFileEntry = resManager.getRawFileEntry("resources/rawfile/configuration.properties");
            Resource resource = rawFileEntry.openRawFile();
            if (resource == null && configuration == null) {
                throw new FileNotFoundException("can not find configuration.properties");
            }
            InputStream in = new BufferedInputStream(resource);
            prop.load(in);
            if (configuration == null) {
                String key = prop.getProperty(API_KEY);
                if (TextUtils.isEmpty(key)) {
                    throw new IllegalArgumentException("No Bugsnag API key set");
                }
                configuration = new Configuration(key);
            }

            loadDetectionConfig(configuration, prop);
            loadEndpointsConfig(configuration, prop);
            loadAppConfig(configuration, prop);

            String maxBreadcrumbs = prop.getProperty(MAX_BREADCRUMBS, configuration.getMaxBreadcrumbs() + "");
            String maxPersistedEvents = prop.getProperty(MAX_PERSISTED_EVENTS,
                configuration.getMaxPersistedEvents() + "");
            String maxPersistedSessions = prop.getProperty(MAX_PERSISTED_SESSIONS,
                configuration.getMaxPersistedSessions() + "");
            String launchDurationMillis = prop.getProperty(LAUNCH_DURATION_MILLIS,
                configuration.getLaunchDurationMillis() + "");
            String sendLaunchCrashesSynchronously = prop.getProperty(SEND_LAUNCH_CRASHES_SYNCHRONOUSLY,
                configuration.getSendLaunchCrashesSynchronously() + "");

            configuration.setMaxBreadcrumbs(Integer.valueOf(maxBreadcrumbs));
            configuration.setMaxPersistedEvents(Integer.valueOf(maxPersistedEvents));
            configuration.setMaxPersistedSessions(Integer.valueOf(maxPersistedSessions));
            configuration.setLaunchDurationMillis(Integer.valueOf(launchDurationMillis));
            configuration.setSendLaunchCrashesSynchronously(Boolean.valueOf(sendLaunchCrashesSynchronously));
        } catch (FileNotFoundException e) {
            if (configuration == null) {
                throw new IllegalArgumentException("No Bugsnag API key set");
            }
        } catch (IOException e) {
            e.getMessage();
        } catch (NumberFormatException e) {
            e.getMessage();
        }
        return configuration;
    }

    /**
     * get string value by key
     *
     * @param key
     * @return value
     */
    public static final String getString(String key) {
        return prop.getProperty(key, "");
    }

    private void loadDetectionConfig(Configuration config, Properties data) {
        String autoTrackSessions = data.getProperty(AUTO_TRACK_SESSIONS, config.getAutoTrackSessions() + "");
        String autoDetectErrors = data.getProperty(AUTO_DETECT_ERRORS, config.getAutoDetectErrors() + "");
        String persistUser = data.getProperty(PERSIST_USER, config.getPersistUser() + "");
        config.setAutoTrackSessions(Boolean.valueOf(autoTrackSessions));
        config.setAutoDetectErrors(Boolean.valueOf(autoDetectErrors));
        config.setPersistUser(Boolean.valueOf(persistUser));
        String str = data.getProperty(SEND_THREADS);
        if (str != null) {
            ThreadSendPolicy sendThreads = ThreadSendPolicy.fromString(str);
            config.setSendThreads(sendThreads);
        }
    }

    private void loadEndpointsConfig(Configuration config, Properties data) {
        if (data.containsKey(ENDPOINT_NOTIFY)) {
            String endpoint = data.getProperty(ENDPOINT_NOTIFY, config.getEndpoints().getNotify());
            String sessionEndpoint = data.getProperty(ENDPOINT_SESSIONS, config.getEndpoints().getSessions());
            config.setEndpoints(new EndpointConfiguration(endpoint, sessionEndpoint));
        }
    }

    private void loadAppConfig(Configuration config, Properties data) {
        String releaseStage = data.getProperty(RELEASE_STAGE, config.getReleaseStage());
        String appVersion = data.getProperty(APP_VERSION, config.getAppVersion());
        String appType = data.getProperty(APP_TYPE, config.getAppType());
        config.setReleaseStage(releaseStage);
        config.setAppVersion(appVersion);
        config.setAppType(appType);
        if (data.containsKey(VERSION_CODE)) {
            String versionCode = data.getProperty(VERSION_CODE);
            config.setVersionCode(Integer.valueOf(versionCode));
        }
        if (data.containsKey(ENABLED_RELEASE_STAGES)) {
            Set<String> enabledReleaseStages = getStrArray(data, ENABLED_RELEASE_STAGES,
                config.getEnabledReleaseStages());
            config.setEnabledReleaseStages(enabledReleaseStages);
        }
        Set<String> discardClasses = getStrArray(data, DISCARD_CLASSES, config.getDiscardClasses());
        if (discardClasses == null) {
            discardClasses = Collections.emptySet();
        }
        config.setDiscardClasses(discardClasses);
        Set<String> projectPackages = getStrArray(data, PROJECT_PACKAGES, Collections.emptySet());
        if (projectPackages == null) {
            projectPackages = Collections.emptySet();
        }
        config.setProjectPackages(projectPackages);
        Set<String> redactedKeys = getStrArray(data, REDACTED_KEYS, config.getRedactedKeys());
        if (redactedKeys == null) {
            redactedKeys = Collections.emptySet();
        }
        config.setRedactedKeys(redactedKeys);
    }

    private Set<String> getStrArray(Properties data, String key, Set<String> defaultSet) {
        String delimitedStr = data.getProperty(key);
        if (TextUtils.isEmpty(delimitedStr)) {
            return defaultSet;
        }
        String[] ary = delimitedStr.split(",");
        HashSet set = new HashSet(new ArrayList(Arrays.asList(ary)));
        return set;
    }
}
